/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "IndexBuffer.h"
#include "Hardware.h"
#include <Gluck.h>

namespace liba
{
namespace lib3d
{
namespace hard
{
namespace directx8
{

IndexBuffer::IndexBuffer(Hardware * hardware, int max_vertex_index)
:	Dependent( hardware ),
	max_vertex_index( max_vertex_index ),
	valid_flag( false ),
	index_buffer( 0 ),
	indices_count( 0 )
{}

IndexBuffer::~IndexBuffer()
{
	release();
}

bool IndexBuffer::is_valid()const
{
	return valid_flag;
}

bool IndexBuffer::update( const int * indices, int indices_count )
{
	//TODO: fix this bug with max_vertex_index
//	if( indices_count > max_vertex_index )
//		return false;
//	if( indices_count < 0x10000 )
		return update<unsigned short>( indices, indices_count, D3DFMT_INDEX16 );
//	return update<unsigned int>( indices, indices_count, D3DFMT_INDEX32 );
}

template<class T>
bool IndexBuffer::update( const int * indices, int indices_count, D3DFORMAT format )
{
	if (!hardware->is_operational())
		return true;

	if( !valid_flag || this->indices_count != indices_count )
	{
		if ( index_buffer )
			index_buffer->Release(); index_buffer = 0;

		this->indices_count = indices_count;
		if( indices_count == 0 )
		{
			valid_flag = true;
			return true;
		}

		hardware->get_device()->CreateIndexBuffer( sizeof(T)*indices_count, D3DUSAGE_WRITEONLY, format, D3DPOOL_MANAGED, &index_buffer, 0 );
		if ( !index_buffer )
			throw Gluck(__FUNCTION__, "hardware->get_device()->CreateIndexBuffer() failed");
	}
	if( indices_count == 0 )
	{
		valid_flag = true;
		return true;
	}

	T * data = 0;
	HRESULT hr = index_buffer->Lock( 0, 0, reinterpret_cast<void **>( &data ), 0 );
	if( FAILED(hr) )
		throw Gluck(__FUNCTION__, "index_buffer->Lock() failed");
	for( int i = 0; i != indices_count; ++i )
	{
		int val = *indices++;
		*data++ = val;
	}
	hr = index_buffer->Unlock();
	valid_flag = true;
	return true;
}

bool IndexBuffer::render( int index_pos, int primitive_count, int vertex_pos, int vertex_count )
{
	if (!hardware->is_operational())
		return true;

	hardware->get_device()->SetIndices( index_buffer );
	hardware->get_device()->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, vertex_pos, vertex_count, index_pos, primitive_count );
	return true;
}

void IndexBuffer::invalidate()
{
//	valid_flag = false; we are managed :)
}

void IndexBuffer::release()
{
	valid_flag = false;

	if( index_buffer )
		int ref_count = index_buffer->Release();
	index_buffer = 0;
}

} // namespace directx8
} // namespace hard
} // namespace lib3d
} // namespace liba

